package com.ruoyi.srmcontract.service.impl;

import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import com.ruoyi.srmcontract.mapper.JacContractItemMapper;
import com.ruoyi.srmcontract.mapper.JacContractItemtoerpMapper;
import com.ruoyi.srmcontract.mapper.JacContractMapper;
import com.ruoyi.srmcontract.domain.JacContract;

import com.ruoyi.srmcontract.domain.JacContractItemtoerp;
import com.ruoyi.srmcontract.service.IJacContractService;


import com.google.common.base.Joiner;

import com.ruoyi.common.constant.Constants;

import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;

/**
 * 合同维护Service业务层处理
 *
 * @author ygx
 * @date 2020-08-04
 */
@Service
public class JacContractServiceImpl implements IJacContractService {
	private static final Logger log = LoggerFactory.getLogger(JacContractServiceImpl.class);

	@Autowired
	private JacContractMapper jacContractMapper;
	@Autowired
	private RedisTemplate<String, Object> redisTemplate;
	@Autowired
	private JacContractItemtoerpMapper jacContractItemtoerpMapper;
	@Autowired
	private JacContractItemMapper jacContractItemMapper;


	/**
	 * 查询合同维护
	 *
	 * @param contractId 合同维护ID
	 * @return 合同维护
	 */
	@Override
	public List<JacContract> selectJacContractById(Long contractId) {
		return jacContractMapper.selectJacContractById(contractId);
	}

    /**
     * 根据uuid获取合同列表
     * @param uuid
     * @return
     */
    public List<JacContract> selectCodeByUuid(String uuid) {
    	return jacContractMapper.selectCodeByUuid(uuid);
    }

	/**
	 * 查询需要导出到Excel的合同物料明细列表
	 *
	 * @param jacContractItem 合同信息
	 * @return 合同信息集合
	 */
	@Override
	public List<JacContract> selectExcelList(JacContract jacContract) {
		return jacContractMapper.selectExcelList(jacContract);
	}

	/**
	 * 查询合同维护列表
	 *
	 * @param 合同搜索条件
	 *
	 * @return 合同列表
	 */
	@Override
	public List<JacContract> selectJacContractList(JacContract jacContract) {
		// 拆分状态字符串
		List<String> statuslist = jacContract.getStatuslist();
		if (statuslist != null && statuslist.size() > 0) {
			String status = "'" + StringUtils.join(statuslist, "','") + "'";
			jacContract.setStatus(status);
		}
		// 修改合同签约开始、终止时间的格式yyyy-mm-dd(字符串)，转为yyyyMMdd
		if (jacContract.getSingStart() != null && !StringUtils.isBlank(jacContract.getSingStart())) {
			jacContract.setSingStart(jacContract.getSingStart().replace("-", "").substring(0, 8));
		}
		if (jacContract.getSingEnd() != null && !StringUtils.isBlank(jacContract.getSingEnd())) {
			jacContract.setSingEnd(jacContract.getSingEnd().replace("-", "").substring(0, 8));
		}
		return jacContractMapper.selectJacContractList(jacContract);
	}

	/**
	 * 查询合同维护日志
	 *
	 * @param jacContractcode 合同号
	 * @return 合同日志
	 */
	@Override
	public List<JacContract> selectLog(JacContract jacContract) {
		return jacContractMapper.selectLog(jacContract);
	}

	/**
	 * 新增合同维护
	 *
	 * @param jacContract 合同维护
	 * @return 结果
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public String insertJacContract(JacContract jacContract) {
		String result = "1";
		HttpServletRequest request = ServletUtils.getRequest();
		String user = request.getHeader(Constants.CURRENT_USERNAME);
		String username = jacContractMapper.selectUserNameById(request.getHeader(Constants.CURRENT_ID));
		String datedate = new SimpleDateFormat("yyyyMMdd").format(new Date());
		String datetime = new SimpleDateFormat("HHmmss").format(new Date());
		// Long date = Long.valueOf(datetime);
		jacContract.setAmount(0.0);
		jacContract.setUntaxamount(0.0);
		jacContract.setCreateusername(username);
		jacContract.setCreateuser(user);
		// jacContract.setContractyear(Long.valueOf(datedate.substring(0,4)));
		jacContract.setCreatedate(Long.valueOf(datedate));
		jacContract.setCreatetime(Long.valueOf(datetime));
		jacContract.setLogdate(Long.valueOf(datedate));
		jacContract.setLogtime(Long.valueOf(datetime));
		jacContract.setLogusername(username);
		jacContract.setLoguser(user);
		jacContract.setStatus("ContractNew");
		if (jacContract.getContractcodeold() != null || "".equals(jacContract.getContractcodeold()))
		{
			try {
				// 写入日志
				String status = jacContract.getStatus();
				jacContract.setOpinion(statusToOpinion(status));
				jacContract.setLogdescribe(statusToDescribe("CopyContract") + "原合同号为：" + jacContract.getContractcodeold());
				jacContractMapper.insertJacContractLog(jacContract);
				// 复制合同明细
				jacContractMapper.copyItem(jacContract);
			} catch (Exception e) {
				log.error("新合同" + jacContract.getContractcode() + "复制老同" + jacContract.getContractcodeold() + "下的物料明细失败！",e);
			return result;
			}
		}
		// 写入日志
		String status = jacContract.getStatus();
		jacContract.setOpinion(statusToOpinion(status));
		jacContract.setLogdescribe(statusToDescribe(status));
		jacContractMapper.insertJacContractLog(jacContract);
		try {
			jacContractMapper.insertJacContract(jacContract);
		} catch (Exception e) {
			if (e instanceof DuplicateKeyException)
			{
				result = "同一供应商，在该基地已存在相同模板、归属年、月、类型的合同，不允许重复添加！";
				return result;
			}
			else {
				result = "新增合同" + jacContract.getContractcode() + "失败，请联系管理员！";
				log.error(result, e);
				TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
				return result;
			}
		}
		return result;
	}

	/**
	 * 修改合同维护
	 *
	 * @param jacContract 合同维护
	 * @return 结果
	 */
	@Override
	public int updateJacContract(JacContract jacContract) {
		HttpServletRequest request = ServletUtils.getRequest();
		String username = jacContractMapper.selectUserNameById(request.getHeader(Constants.CURRENT_ID));
		String user = request.getHeader(Constants.CURRENT_USERNAME);
		String datedate = new SimpleDateFormat("yyyyMMdd").format(new Date());
		String datetime = new SimpleDateFormat("HHmmss").format(new Date());
		// Long date = Long.valueOf(datetime);
		jacContract.setLogdate(Long.valueOf(datedate));
		jacContract.setLogtime(Long.valueOf(datetime));
		jacContract.setLoguser(user);
		jacContract.setLogusername(username);
		return jacContractMapper.updateJacContract(jacContract);
	}

	/**
	 * 修改合同状态
	 *
	 * @param jacContract 合同维护
	 * @return 结果
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public String updateContractStatus(Map<String, List<JacContract>> datas) {
		String result = "1";
		List<String> statusCheck = new ArrayList<>();
		List<String> jflow = new ArrayList<>();
		HttpServletRequest request = ServletUtils.getRequest();
		String user = request.getHeader(Constants.CURRENT_USERNAME);
		String username = jacContractMapper.selectUserNameById(request.getHeader(Constants.CURRENT_ID));
		String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
		String crsj = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
		String companycode= "";

		List<JacContract> jacContracts = datas.get("datas");
		for (JacContract jacContract : jacContracts) {
			companycode = jacContract.getCompanycode();
			//检查是否允许变更状态
			String itemNameRe = statusCheck(jacContract.getStatus(), jacContract.getContractcode(),
					jacContract.getCompanycode(),crsj);
			if (!"1".equals(itemNameRe)) {
				statusCheck.add(itemNameRe);
			}
			else
			{
				if ("1".equals(itemNameRe) && "FlowConfirmeing".equals(jacContract.getStatus())) {
				jflow.add(jacContract.getContractcode());
			       }
				if ( !"FlowConfirmeing".equals(jacContract.getStatus()))
				{
					//在审批流程中维护通过驳回的数据，status状态不需要更新，只需要更新jflowstatus，流程完成后更新status
				if (jacContract.getJflowstatus() == "EndConfirmed" || jacContract.getJflowstatus() == "ConfirmedNo")
				{
					jacContract.setStatus(null);
				}
				jacContract.setLoguser(user);
				jacContract.setLogusername(username);
				jacContract.setLogdate(Long.valueOf(date.substring(0, 8)));
				jacContract.setLogtime(Long.valueOf(date.substring(8, 14)));
				// 写入日志
				String status = jacContract.getStatus();
				jacContract.setOpinion(statusToOpinion(status));
				jacContract.setLogdescribe(statusToDescribe(status));
				jacContractMapper.insertJacContractLog(jacContract);
				// 更新合同状态
				try {
					//因取消了送签状态，发布后由Publish直接变更为Confirmeing（审核）20201209byygx
					if ("Publish".equals(jacContract.getStatus()))
					{
						jacContract.setStatus("Confirmeing");
					}
					jacContractMapper.updateContractStatus(jacContract);
				} catch (Exception e) {
					if ("InWork".equals(jacContract.getStatus()))
					{
						log.error(jacContract.getContractcode() + " 合同状态更新失败！开始删除中间池新增数据",e);
						jacContractItemtoerpMapper.delErpByConcode(jacContract.getContractcode(),crsj,username,"A");
						result = jacContract.getContractcode() + " 合同状态更新失败";
					}
					if ("Delete".equals(jacContract.getStatus()))
					{
						log.error(jacContract.getContractcode() + " 合同状态更新失败！开始删除中间池作废数据",e);
						jacContractItemtoerpMapper.delErpByConcode(jacContract.getContractcode(),crsj,username,"D");
						result = jacContract.getContractcode() + " 合同状态更新失败";
					}
					result = jacContract.getContractcode() + " 合同状态更新失败";
					log.error(result);
					TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
					return result;
				}
			}
			}
		}
		if (statusCheck.size() > 0 && statusCheck != null) {
			return Joiner.on(';').join(statusCheck);
		}
		//假如存在启动流程的数据
		if ((statusCheck.size() == 0 || statusCheck == null) && jflow.size() > 0 && jflow != null)
			{
			String jflowid = "006";
			String uuid = UUID.randomUUID().toString();
			String param = Joiner.on(',').join(jflow);
			String type = "contract";
			// 写入日志,变更合同状态
			for (String flowcontract : jflow)
			{
				JacContract jacContract = new JacContract();
			jacContract.setContractcode(flowcontract);;
			jacContract.setOpinion("送签流程审批中，等待审批完成");
			jacContract.setLogdescribe("合同启动流程");
			jacContract.setCompanycode(companycode);
			jacContract.setCreateusername(username);
			jacContract.setCreateuser(user);
			jacContract.setLoguser(user);
			jacContract.setLogusername(username);
			jacContract.setLogdate(Long.valueOf(date.substring(0, 8)));
			jacContract.setLogtime(Long.valueOf(date.substring(8, 14)));
			jacContract.setStatus(null);
			jacContractMapper.insertJacContractLog(jacContract);

		try {
				jacContractMapper.updateContractStatus(jacContract);
			} catch (Exception e){
				log.error("送签启动流程，合同状态变更失败，请联系管理员!",e);
				return "送签启动流程，合同状态变更失败，请联系管理员!";
			}
		   }
			try {
				jacContractMapper.insertFlow(jflowid, uuid, param, type, username, crsj);
			} catch (Exception e) {
				log.error("送签启动流程，流程数据写入失败，请联系管理员!",e);
				return "送签启动流程，流程数据写入失败，请联系管理员!";
			}
			return "uuid" + "'" + uuid + "'" + "&DSPHT=" + param;
		 }

		return result;
	}

    /**
     * 写入日志描述
     * @param status
     * @return
     */
	public String statusToOpinion(String status) {
		if ("ContractNew".equals(status)) {
			return "新增合同，请确认后发布或送签";
		}
		if ("Publish".equals(status)) {
			return "发布成功，请确认合同";
		}
		if ("VendorConfirmed".equals(status)) {
			return "发布成功，等待供应商确认";
		}
		if ("VendorConfirmedno".equals(status)) {
			return "供应商拒绝，请联系供应商";
		}
		if ("Confirmeing".equals(status)) {
			return "送签审批中，等待审批完成";
		}
		if ("FlowConfirmeing".equals(status)) {
			return "送签流程审批中，等待审批完成";
		}
		if ("EndConfirmed".equals(status)) {
			return "审批通过，请生效合同";
		}
		if ("ConfirmedNo".equals(status)) {
			return "审批拒绝，请联系审批人员";
		}
		if ("InWork".equals(status)) {
			return "合同已生效，请在ERP合同管理页面查询";
		}
		if ("Cancel".equals(status)) {
			return "合同已取消";
		}
		if ("Delete".equals(status)) {
			return "合同已废止";
		} else {
			return "0";
		}
	}

	/**
	 * 检查是否允许改变合同状态
	 * @param status   前台传的，变更后的状态
	 * @param contracode  合同号
	 * @param companycode 公司编号
	 * @return 是否成功
	 */
	public String statusCheckdelete1217(String status, String contracode, String companycode,String crsj) {
		// 获取合同当前状态
		String s = jacContractMapper.checkStatus(contracode);

		if ("Publish".equals(status)) {
			if (!"ContractNew".equals(s) && !"VendorConfirmedno".equals(s) && !"ConfirmedNo".equals(s)) {
				return "合同" + contracode + "不允许发布，只有新增，供应商拒绝，审批拒绝状态的允许发布！";
			}
           if (!jacContractItemMapper.checkItemExists(contracode))
           {
        	   return "合同" + contracode + "下无物料明细，不允许发布！";
           }
		}

		//2020年12月9号ygx删除，发布后状态直接变为送签
/*		if ("Confirmeing".equals(status) || "FlowConfirmeing".equals(status)) {
			if (!"ContractNew".equals(s) && !"Publish".equals(s) && !"ConfirmedNo".equals(s)) {
				return "合同" + contracode + "不允许送签，只有新增，发布，审批拒绝状态的允许送签！";
			}
		}*/

		if ("Publish".equals(status) || "VendorConfirmed".equals(status) || "InWork".equals(status) || "Confirmeing".equals(status) || "FlowConfirmeing".equals(status))
		{
			List<String> itemnames = jacContractMapper.checkDate(contracode);
			if (itemnames.size() != 0 && itemnames != null) {
				String result = Joiner.on(",").join(itemnames);
				return "合同" + contracode + "发布失败！合同中，物料" + result + "的生效时间必须在合同生效、失效时间之间";
			}

			List<Map<String, String>> items = jacContractMapper.checkItemUnique(contracode);
			if (items.size() > 0 && items != null) {
				String resulttmp = "";
				String oldcontractcode = "";
				String itemcode = "";
				String itemname = "";
				List<String> listResult = new ArrayList<String>();
				for (Map<String, String> item : items) {
					oldcontractcode = item.get("contractcode");
					itemcode = item.get("itemcode");
					itemname = item.get("itemname");
					resulttmp = "合同 " + oldcontractcode + "中的物料 " + itemcode + "(" + itemname + ")";
					listResult.add(resulttmp);
				}
				String result = "合同 " + contracode + " 中的物料与其它合同的物料生效时间相同，请修改生效时间！冲突的数据为："
						+ Joiner.on(',').join(listResult);
				return result;
			}
		}

		if ("EndConfirmed".equals(status)) {
			if (!"FlowConfirmeing".equals(s) && !"Confirmeing".equals(s)) {
				return "合同" + contracode + "不允许审批，只能审批状态为审批中的合同！";
			}
		}

		if ("InWork".equals(status)) {
			if (!"EndConfirmed".equals(s)) {
				return "合同" + contracode + "生效失败！只允许生效审批通过的合同";
			} else {
				// 按规则检查是否存在erp号，存在则返回原erp合同号，不存在则生成
				HttpServletRequest request = ServletUtils.getRequest();
				@SuppressWarnings("unused")
				String user = request.getHeader(Constants.CURRENT_USERNAME);
				String username = jacContractMapper.selectUserNameById(request.getHeader(Constants.CURRENT_ID));
				String erpcontractcode = checkErpCode(contracode, companycode);

				// 获取需要插入erp中间池的合同明细，并循环插入erp合同中间池
				for (JacContractItemtoerp adderp : jacContractItemtoerpMapper.selectToErpAdd(contracode)) {
					adderp.setErpcontractcode(erpcontractcode);
					// 获取erpid和erpnum
					Map<String, Long> maxmap = selectMaxErpId(erpcontractcode, adderp.getItemcode());
					if (maxmap.get("code") == 500)
					{
						return "合同" + erpcontractcode + "下的物料" + adderp.getItemcode() + "生成ERP行号与价格号异常！请联系管理员！";
					}
					adderp.setErpid(maxmap.get("itemerpid"));
					adderp.setErpnum(maxmap.get("erpnum"));
					adderp.setCreateusername(username);
					adderp.setCrsj(crsj);
					try {
						jacContractItemtoerpMapper.insertJacContractItemtoerp(adderp);
					} catch (Exception e) {
						redisTemplate.delete("Max_ERPId:" + erpcontractcode);
						redisTemplate.delete("Max_ERPNum:" + erpcontractcode + adderp.getItemcode());
						redisTemplate.delete("Max_ITEMId:" + erpcontractcode + adderp.getItemcode());
						log.error("合同" + contracode + "废止数据写入Erp中间池失败，开始删除已经写入的中间池新增数据",e);
						jacContractItemtoerpMapper.delErpByConcode(erpcontractcode,crsj,username,"A");
						log.error("合同" + erpcontractcode + "下的物料" + adderp.getItemcode() + "传入ERP中间池异常，已停止生效！请联系管理员！");
						return "合同" + erpcontractcode + "下的物料" + adderp.getItemcode() + "传入ERP中间池异常，已停止生效！请联系管理员！";
					}
					redisTemplate.delete("Max_ERPNum:" + erpcontractcode + adderp.getItemcode());
					redisTemplate.delete("Max_ITEMId:" + erpcontractcode + adderp.getItemcode());
				}
				redisTemplate.delete("Max_ERPId:" + erpcontractcode);
				return "1";
			}
		}

		if ("Cancel".equals(status)) {
			if ("ContractNew".equals(s)) {
				return "合同" + contracode + "取消失败！合同为新增状态，请直接删除！";
			}
			if (!"Publish".equals(s)) {
				return "合同" + contracode + "取消失败！只允许取消发布状态的合同";
			}
			else {
				return "1";
			}

		}

		if ("Delete".equals(status)) {
			if (!"EndConfirmed".equals(s) && !"InWork".equals(s)) {
				return "合同" + contracode + "废止失败！只允许废止审核通过和生效状态的合同";
			}
			if ("InWork".equals(s))
			{
			try {
				jacContractItemtoerpMapper.selectToErpDel(
						ServletUtils.getRequest().getHeader(Constants.CURRENT_USERNAME), contracode, crsj);
			} catch (Exception e) {
			    log.error("合同" + contracode + "废止数据写入Erp中间池失败，开始删除已经写入的中间池废止数据",e);
				jacContractItemtoerpMapper.delErpByConcode(contracode,crsj,ServletUtils.getRequest().getHeader(Constants.CURRENT_USERNAME),"D");
			    return "合同" + contracode + "废止数据写入Erp中间池失败，请联系管理员！";
			}
			}
			else {
				return "1";
			}
		}

		return "1";
	}

	/**
	 * 生成日志中的状态操作
	 * @param status
	 * @return
	 */
	public String statusToDescribe(String status) {
		if ("CopyContract".equals(status)) {
			return "复制合同";
		}
		if ("ContractNew".equals(status)) {
			return "新增合同";
		}
		if ("Publish".equals(status)) {
			return "发布合同";
		}
		if ("VendorConfirmed".equals(status)) {
			return "供应商确认";
		}
		if ("VendorConfirmedno".equals(status)) {
			return "供应商拒绝";
		}
		if ("Confirmeing".equals(status)) {
			return "合同送签";
		}
		if ("FlowConfirmeing".equals(status)) {
			return "合同启动流程";
		}
		if ("EndConfirmed".equals(status)) {
			return "审批通过";
		}
		if ("ConfirmedNo".equals(status)) {
			return "审批拒绝";
		}
		if ("InWork".equals(status)) {
			return "生效合同";
		}
		if ("Cancel".equals(status)) {
			return "取消合同";
		}
		if ("Delete".equals(status)) {
			return "废止合同";
		} else {
			return "0";
		}
	}

	/**
	 * 通过合同编号获取公司名称、采购部门名称、供应商代号、合同年度获取ERP合同号
	 *
	 * @Param 合同号
	 * @return ERP合同号
	 */
	public String checkErpCodedelete1217(String contractCode, String companycode) {
		String erpcontractcode = jacContractMapper.checkErpCode(contractCode);
		if (erpcontractcode == null || StringUtils.isBlank(erpcontractcode)) {
			JacContract jc = jacContractMapper.redisErpCode(contractCode);
			String redisErpCode = jc.getCompanycode() + jc.getDepartmentcode() + jc.getContracttype()
					+ jc.getContractyear();
			if (!redisTemplate.hasKey(redisErpCode)) {
				erpcontractcode = createContractCode(companycode, "ERPHT");
				redisTemplate.opsForValue().set(redisErpCode, erpcontractcode);
				redisTemplate.expire(redisErpCode, 10, TimeUnit.MINUTES);
			} else {
				erpcontractcode = (String) redisTemplate.opsForValue().get(redisErpCode);
			}
			return erpcontractcode;
		}
		return erpcontractcode;
	}


	public String checkErpCode(String contractCode, String companycode) {
		  //通过合同编号获取公司名称、采购部门名称、供应商代号、合同年度获取ERP合同号（判断erp合同号是否存在）
		  String erpcontractcode = jacContractMapper.checkErpCode(contractCode);
		  if (erpcontractcode == null || StringUtils.isBlank(erpcontractcode)) {
		   //不存在需要进行redis流水，生成新的流水号
		   JacContract jc = jacContractMapper.redisErpCode(contractCode);
		   String redisErpCode = "ErpCode:" + jc.getCompanycode() + jc.getDepartmentcode() + jc.getContractyear() + jc.getVendorcode();
		   //假如redisErpCode为空，生成流水号，并将流水号写入redis
		   if (!redisTemplate.hasKey(redisErpCode)) {
		    erpcontractcode = createContractCode(companycode, "ERPHT");
		    redisTemplate.opsForValue().set(redisErpCode, erpcontractcode);
		    redisTemplate.expire(redisErpCode, 3, TimeUnit.DAYS);
		   } else {
		    erpcontractcode = (String) redisTemplate.opsForValue().get(redisErpCode);
		   }
		   return erpcontractcode;
		  }
		  return erpcontractcode;
		 }

	/**
	 * 批量修改合同维护
	 *
	 * @param jacContract信息
	 *
	 * @return 修改受影响行数
	 */
	@Override
	public int updateJacContracts(Map<String, List<JacContract>> datas) {
		List<JacContract> jacContracts = datas.get("datas");
		for (JacContract jacContract : jacContracts) {
			int i = jacContractMapper.updateJacContract(jacContract);
			if (i != 1) {
				return 0;
			}
		}
		return 1;
	}

	/**
	 * 删除合同维护对象
	 *
	 * @param ids 需要删除的数据ID
	 * @return 结果
	 */
	@Override
	public String deleteJacContractByIds(String ids) {
		String result = "1";
		List<String> checkStatus = new ArrayList<>();
		String[] id = ids.split(",");
		for (String contractId : id) {
			String contractcode = jacContractMapper.selectStatus(Long.valueOf(contractId));
			if (!StringUtils.isBlank(contractcode) && !"".equals(contractcode)) {
				checkStatus.add(contractcode);
			} else {
				jacContractMapper.deleteItemById(Long.valueOf(contractId));
				try {
					jacContractMapper.deleteJacContractById(Long.valueOf(contractId));
				} catch (Exception e) {
					log.error( "合同模板ID" + contractId + "删除失败，请联系管理员！",e);
					result = "合同模板ID" + contractId + "删除失败，请联系管理员！";
				}
			}
		}
		if (checkStatus.size() > 0 && checkStatus != null) {
			result = "只允许删除新增状态的合同，合同" + Joiner.on(",").join(checkStatus) + "不是新增状态，不允许删除！";
			log.info(result);
			return result;
		}
		return result;
	}

	/**
	 * 通过redis自增生成合同号（如：HTBJ202008030001）
	 *
	 * @param prefix 合同号前缀 companycode 公司code factoryType 公司别名
	 * @return 合同号
	 */
	public String createContractCode(String companycode, String prefix) {
		String factoryType = jacContractMapper.selectFactoryType(companycode);
		String datetime = new SimpleDateFormat("yyyyMMdd").format(new Date());
		String key = prefix + factoryType + datetime;

		// 然后把 时间戳和优化后的 ID 拼接
		String code = null;
		try {
			// 查询 key 是否存在， 不存在返回 1 ，存在的话则自增加1
			Long autoID = redisTemplate.opsForValue().increment(key, 1);
			log.info("获取autoID值：" + autoID);
			// 这里是 4 位id，如果位数不够可以自行修改 ，下面的意思是 得到上面 key 的 值，位数为 4 ，不够的话在左边补 0 ，比如 110 会变成
			// 0110
			String value = StringUtils.leftPad(String.valueOf(autoID), 4, "0");
			code = MessageFormat.format("{0}{1}", key, value);
			// 设置三天过期
			redisTemplate.expire(key, 3, TimeUnit.DAYS);
		} catch (Exception e) {
			log.error("连接redis生成流水号异常！",e);
		}
		return code;
	}

	/**
	 * 获取erpid/erpnum通过redis为erpid加锁，实现并发锁
	 *
	 * @param erpcontractcode ERP合同号
	 * @return 最大Id
	 */
	public Map<String, Long> selectMaxErpId(String erpcontractcode, String itemcode) {
		String idkey = "Max_ERPId:" + erpcontractcode;
		String itemid = "Max_ITEMId:" + erpcontractcode + itemcode;
		String numkey = "Max_ERPNum:" + erpcontractcode + itemcode;
		String redislock = "RedisLock:" + erpcontractcode + itemcode;
		Map<String, Long> result = new HashMap<>();
		Long erpid = (long) 0;
		Long itemerpid = (long) 0;
		Long erpnum = (long) 0;

		try {
			// 查询 redis是否存在item对应的erpid， 不存在则根据erpid生成（按照程序执行顺序，itemid缓存生成后，erpnum缓存也会生成）
			if (!redisTemplate.hasKey(itemid)) {
				// 判断是否已被锁定（redis并发锁），在从数据库查询数据前循环判断锁是否存在。存在循环取20次itemerpid的redis缓存，取到后或20次退出
				if (redisTemplate.hasKey(redislock)) {
					int lockcount = 0;
					boolean exists;
					do {
						exists = redisTemplate.hasKey(itemid);
						lockcount++;
					}
					while (exists == false && lockcount < 20);

					if (exists == false)
					{
						itemerpid = jacContractMapper.selectItemErpId(erpcontractcode, itemcode);
					}
					else {
						itemerpid = Long.valueOf(redisTemplate.opsForValue().get(itemid).toString());
					}
				}
				else {
					// 设置并发锁并获取mysql数据，如果存在则返回erpid，不存在则返回0，并设置并发锁失效时间为2秒(失效时间内需确保进程能够从数据库中完成数据取值并写入redis缓存)
					redisTemplate.opsForValue().set(redislock, "lock",2, TimeUnit.SECONDS);
					/* redisTemplate.expire(redislock, 2000, TimeUnit.SECONDS); */
					itemerpid = jacContractMapper.selectItemErpId(erpcontractcode, itemcode);
				}

				if (itemerpid == 0)
				{
					if (!redisTemplate.hasKey(idkey))
				{
					erpid = jacContractMapper.selectMaxErpId(erpcontractcode);
				   if (erpid == 0)
				    {
				    erpid = redisTemplate.opsForValue().increment(idkey, 1);
					redisTemplate.expire(idkey, 10, TimeUnit.MINUTES);
				    }
				else
				{
					erpid = erpid + 1;
					redisTemplate.opsForValue().set(idkey, erpid.intValue(), 10, TimeUnit.MINUTES);
							/* redisTemplate.expire(idkey, 10, TimeUnit.MINUTES); */
				}
				}
				else {
					erpid = redisTemplate.opsForValue().increment(idkey, 1);
					redisTemplate.expire(idkey, 10, TimeUnit.MINUTES);
				}
					itemerpid = erpid;
			}

				redisTemplate.opsForValue().set(itemid, itemerpid.intValue(), 10, TimeUnit.MINUTES);
				/* redisTemplate.expire(itemid, 10, TimeUnit.MINUTES); */
			}

			if (!redisTemplate.hasKey(numkey))

			{
				erpnum = jacContractMapper.selectMaxErpNum(erpcontractcode, itemcode);
				erpnum = redisTemplate.opsForValue().increment(numkey, erpnum + 1);
				redisTemplate.expire(numkey, 10, TimeUnit.MINUTES);
			} else {
				erpnum = redisTemplate.opsForValue().increment(numkey, 1);
				redisTemplate.expire(numkey, 10, TimeUnit.MINUTES);
			}
		} catch (Exception e) {
			redisTemplate.delete(idkey);
			redisTemplate.delete(itemid);
			redisTemplate.delete(numkey);
			redisTemplate.delete(redislock);
			log.error(erpcontractcode + itemcode +"获取erpid/erpnum失败：",e);
			result.put("code",(long)500);
		}
		//erpid/erpnum获取完毕，且已写入redis缓存，删除并发锁
		redisTemplate.delete(redislock);
		result.put("itemerpid", itemerpid);
		result.put("erpnum", erpnum);
		result.put("code",(long)0);
		return result;
	}

	/**
	 * 枚举判断前台传入状态是否属于约定状态
	 * @author ygx
	 *
	 */
	/*
	 * public enum status { ContractNew, Publish, VendorConfirmed,
	 * VendorConfirmedno, Confirmeing, EndConfirmed, ConfirmedNo, InWork, Cancel,
	 * Delete }
	 */
	/**
	 * 删除合同维护信息
	 *
	 * @param contractId 合同维护ID
	 * @return 结果
	 */
	public int deleteJacContractById(Long contractId) {
		//删除合同明细
		jacContractMapper.deleteItemById(contractId);
		return jacContractMapper.deleteJacContractById(contractId);
	}

    /**
     * 根据参数类型获取参数值（比如传入参数类型ContractYear 获取定义的合同年份）
     * @param paramtype
     * @return
     */
	@Override
    public HashMap<String,String[]> getContractyear(String paramtype)
    {
    	HashMap<String, String[]> m = new HashMap<>();
    	m.put("paramvalue",jacContractMapper.getContractyear(paramtype));
    	return m;
    }

    /**
	 * 检查是否允许改变合同状态
	 * @param status   前台传的，变更后的状态
	 * @param contracode  合同号
	 * @param companycode 公司编号
	 * @return 是否成功
	 */
	public String statusCheck(String status, String contracode, String companycode,String crsj) {
		// 获取合同当前状态
		String s = jacContractMapper.checkStatus(contracode);

		if ("Publish".equals(status)) {
			if (!"ContractNew".equals(s) && !"VendorConfirmedno".equals(s) && !"ConfirmedNo".equals(s)) {
				return "合同" + contracode + "不允许发布，只有新增，供应商拒绝，审批拒绝状态的允许发布！";
			}
           if (!jacContractItemMapper.checkItemExists(contracode))
           {
        	   return "合同" + contracode + "下无物料明细，不允许发布！";
           }
		}

		if ("Publish".equals(status) || "VendorConfirmed".equals(status) || "InWork".equals(status) || "Confirmeing".equals(status) || "FlowConfirmeing".equals(status))
		{
			List<String> itemnames = jacContractMapper.checkDate(contracode);
			if (itemnames.size() != 0 && itemnames != null) {
				String result = Joiner.on(",").join(itemnames);
				return "合同" + contracode + "发布失败！合同中，物料" + result + "的生效时间必须在合同生效、失效时间之间";
			}

			List<Map<String, String>> items = jacContractMapper.checkItemUnique(contracode);
			if (items.size() > 0 && items != null) {
				String resulttmp = "";
				String oldcontractcode = "";
				String itemcode = "";
				String itemname = "";
				List<String> listResult = new ArrayList<String>();
				for (Map<String, String> item : items) {
					oldcontractcode = item.get("contractcode");
					itemcode = item.get("itemcode");
					itemname = item.get("itemname");
					resulttmp = "合同 " + oldcontractcode + "中的物料 " + itemcode + "(" + itemname + ")";
					listResult.add(resulttmp);
				}
				String result = "合同 " + contracode + " 中的物料与其它合同的物料生效时间相同，请修改生效时间！冲突的数据为："
						+ Joiner.on(',').join(listResult);
				return result;
			}
		}

		if ("EndConfirmed".equals(status)) {
			if (!"FlowConfirmeing".equals(s) && !"Confirmeing".equals(s)) {
				return "合同" + contracode + "不允许审批，只能审批状态为审批中的合同！";
			}
		}

		if ("InWork".equals(status)) {
			if (!"EndConfirmed".equals(s)) {
				return "合同" + contracode + "生效失败！只允许生效审批通过的合同";
			} else {
				// 按规则检查是否存在erp号，存在则返回原erp合同号，不存在则生成
				HttpServletRequest request = ServletUtils.getRequest();
				@SuppressWarnings("unused")
				String user = request.getHeader(Constants.CURRENT_USERNAME);
				String username = jacContractMapper.selectUserNameById(request.getHeader(Constants.CURRENT_ID));
				String erpcontractcode = checkErpCode(contracode, companycode);

				// 获取需要插入erp中间池的合同明细，并循环插入erp合同中间池
				for (JacContractItemtoerp adderp : jacContractItemtoerpMapper.selectToErpAdd(contracode)) {
					adderp.setErpcontractcode(erpcontractcode);
					// 获取erpid和erpnum
					Map<String, Long> maxmap = selectMaxErpId(erpcontractcode, adderp.getItemcode());
					if (maxmap.get("code") == 500)
					{
						return "合同" + erpcontractcode + "下的物料" + adderp.getItemcode() + "生成ERP行号与价格号异常！请联系管理员！";
					}
					adderp.setErpid(maxmap.get("itemerpid"));
					adderp.setErpnum(maxmap.get("erpnum"));
					adderp.setCreateusername(username);
					adderp.setCrsj(crsj);
					try {
						jacContractItemtoerpMapper.insertJacContractItemtoerp(adderp);
					} catch (Exception e) {
						redisTemplate.delete("Max_ERPId:" + erpcontractcode);
						redisTemplate.delete("Max_ERPNum:" + erpcontractcode + adderp.getItemcode());
						redisTemplate.delete("Max_ITEMId:" + erpcontractcode + adderp.getItemcode());
						log.error("合同" + contracode + "废止数据写入Erp中间池失败，开始删除已经写入的中间池新增数据",e);
						jacContractItemtoerpMapper.delErpByConcode(erpcontractcode,crsj,username,"A");
						log.error("合同" + erpcontractcode + "下的物料" + adderp.getItemcode() + "传入ERP中间池异常，已停止生效！请联系管理员！");
						return "合同" + erpcontractcode + "下的物料" + adderp.getItemcode() + "传入ERP中间池异常，已停止生效！请联系管理员！";
					}
					redisTemplate.delete("Max_ERPNum:" + erpcontractcode + adderp.getItemcode());
					redisTemplate.delete("Max_ITEMId:" + erpcontractcode + adderp.getItemcode());
				}
				redisTemplate.delete("Max_ERPId:" + erpcontractcode);
				return "1";
			}
		}

		if ("Cancel".equals(status)) {
			if ("ContractNew".equals(s)) {
				return "合同" + contracode + "取消失败！合同为新增状态，请直接删除！";
			}
			if (!"Publish".equals(s)) {
				return "合同" + contracode + "取消失败！只允许取消发布状态的合同";
			}
			else {
				return "1";
			}

		}

		if ("Delete".equals(status)) {
			if (!"EndConfirmed".equals(s) && !"InWork".equals(s)) {
				return "合同" + contracode + "废止失败！只允许废止审核通过和生效状态的合同";
			}
			if ("InWork".equals(s))
			{
			try {
				jacContractItemtoerpMapper.selectToErpDel(
						ServletUtils.getRequest().getHeader(Constants.CURRENT_USERNAME), contracode, crsj);
			} catch (Exception e) {
			    log.error("合同" + contracode + "废止数据写入Erp中间池失败，开始删除已经写入的中间池废止数据",e);
				jacContractItemtoerpMapper.delErpByConcode(contracode,crsj,ServletUtils.getRequest().getHeader(Constants.CURRENT_USERNAME),"D");
			    return "合同" + contracode + "废止数据写入Erp中间池失败，请联系管理员！";
			}
			}
			else {
				return "1";
			}
		}

		return "1";
	}

	@Async("taskExecutor")
	public Future<String> contractcodeToErp  (JacContractItemtoerp adderp, String erpcontractcode, String username, String crsj, String contracode)
	{
		String result = "1";
		adderp.setErpcontractcode(erpcontractcode);
		// 获取erpid和erpnum
		Map<String, Long> maxmap = selectMaxErpId(erpcontractcode, adderp.getItemcode());
		if (maxmap.get("code") == 500)
		{
			result = "合同" + erpcontractcode + "下的物料" + adderp.getItemcode() + "生成ERP行号与价格号异常！请联系管理员！";
		}
		adderp.setErpid(maxmap.get("itemerpid"));
		adderp.setErpnum(maxmap.get("erpnum"));
		adderp.setCreateusername(username);
		adderp.setCrsj(crsj);
		try {
			jacContractItemtoerpMapper.insertJacContractItemtoerp(adderp);
		} catch (Exception e) {
			redisTemplate.delete("Max_ERPId:" + erpcontractcode);
			redisTemplate.delete("Max_ERPNum:" + erpcontractcode + adderp.getItemcode());
			redisTemplate.delete("Max_ITEMId:" + erpcontractcode + adderp.getItemcode());
			log.error("合同" + contracode + "废止数据写入Erp中间池失败，开始删除已经写入的中间池新增数据",e);
			jacContractItemtoerpMapper.delErpByConcode(erpcontractcode,crsj,username,"A");
			log.error("合同" + erpcontractcode + "下的物料" + adderp.getItemcode() + "传入ERP中间池异常，已停止生效！请联系管理员！");
			result =  "合同" + erpcontractcode + "下的物料" + adderp.getItemcode() + "传入ERP中间池异常，已停止生效！请联系管理员！";
		}
		redisTemplate.delete("Max_ERPNum:" + erpcontractcode + adderp.getItemcode());
		redisTemplate.delete("Max_ITEMId:" + erpcontractcode + adderp.getItemcode());
		return new AsyncResult<>("s");
	}

	@Async
	public Future<String> doReturn(int i){
	try {
	// 这个方法需要调用500毫秒
	Thread.sleep(500);
	} catch (InterruptedException e) {
	e.printStackTrace();
	}
	// 消息汇总
	return new AsyncResult<>(String.format("这个是第{%s}个异步调用的证书", i));

	}

}



